package com.anmong.cloud.cloudcommon.config.feign;

import com.anmong.cloud.cloudcommon.exception.ApiInvokeException;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.type.TypeFactory;
import feign.FeignException;
import feign.Response;
import feign.Util;
import feign.codec.DecodeException;
import feign.codec.Decoder;
import org.apache.commons.lang3.StringUtils;
import java.io.IOException;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

public class FeignResultDecoder implements Decoder {

    /**
     * 使用我们自己配置好的objectMapper解决localdatetime序列化问题
     */

    private ObjectMapper objectMapper;

    public FeignResultDecoder(ObjectMapper objectMapper){
        this.objectMapper = objectMapper;
    }

    /**
     * 返回结构是统一的R类型，返回数据统一包装在data中，我们需要统一解码成方法返回的类型，由于data是集合，所以要判断是否是集合
     * @param response
     * @param type
     * @return
     * @throws IOException
     * @throws DecodeException
     * @throws FeignException
     */
    @Override
    public Object decode(Response response, Type type) throws IOException, DecodeException, FeignException {
        if (response.body() == null) {
            throw new ApiInvokeException("返回体为空");
        }
        String bodyStr = Util.toString(response.body().asReader(Util.UTF_8));
        if(StringUtils.isNotEmpty(bodyStr)){
            //先解析统一格式
            JsonNode result = objectMapper.readTree(bodyStr);
            JsonNode targetList = result.get("data");
            if (!targetList.isArray()){
                throw new ApiInvokeException("返回数据结构不正确" + bodyStr);
            }
            if (targetList.size() > 0){
                Object target = null;
                if (type instanceof ParameterizedType) {
                    ParameterizedType pt = (ParameterizedType) type;
                    Type[] types = pt.getActualTypeArguments();
                    //是集合类型，直接解析
                    if (types.length > 0) {
                        //最终目标类
                        target = json2obj(targetList.toString(), type);
                    }
                }
                else {
                    target = json2obj(targetList.get(0).toString(), type);
                }
                return target;
            }
        }
        return null;
    }

    public <T> T json2obj(String jsonStr, Type targetType) {
        try {
            JavaType javaType = TypeFactory.defaultInstance().constructType(targetType);
            return objectMapper.readValue(jsonStr, javaType);
        } catch (IOException e) {
            throw new ApiInvokeException("返回数据结构不正确" + jsonStr, e);
        }
    }


}
